home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / libgimp / gimpwidgets.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-15  |  40.1 KB  |  1,402 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpwidgets.c
  5.  * Copyright (C) 2000 Michael Natterer <mitch@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <string.h>
  26.  
  27. #include <gtk/gtk.h>
  28.  
  29. #include "gimpchainbutton.h"
  30. #include "gimphelpui.h"
  31. #include "gimppixmap.h"
  32. #include "gimpunitmenu.h"
  33. #include "gimpwidgets.h"
  34. #include "gimpmath.h"
  35.  
  36. #include "libgimp-intl.h"
  37.  
  38.  
  39. /*
  40.  *  Widget Constructors
  41.  */
  42.  
  43. /**
  44.  * gimp_option_menu_new:
  45.  * @menu_only: #TRUE if the function should return a #GtkMenu only.
  46.  * @...:       A #NULL terminated @va_list describing the menu items.
  47.  *
  48.  * Returns: A #GtkOptionMenu or a #GtkMenu (depending on @menu_only).
  49.  **/
  50. GtkWidget *
  51. gimp_option_menu_new (gboolean            menu_only,
  52.  
  53.               /* specify menu items as va_list:
  54.                *  const gchar    *label,
  55.                *  GtkSignalFunc   callback,
  56.                *  gpointer        data,
  57.                *  gpointer        user_data,
  58.                *  GtkWidget     **widget_ptr,
  59.                *  gboolean        active
  60.                */
  61.  
  62.                ...)
  63. {
  64.   GtkWidget *menu;
  65.   GtkWidget *menuitem;
  66.  
  67.   /*  menu item variables  */
  68.   const gchar    *label;
  69.   GtkSignalFunc   callback;
  70.   gpointer        data;
  71.   gpointer        user_data;
  72.   GtkWidget     **widget_ptr;
  73.   gboolean        active;
  74.  
  75.   va_list args;
  76.   gint    i;
  77.   gint    initial_index;
  78.  
  79.   menu = gtk_menu_new ();
  80.  
  81.   /*  create the menu items  */
  82.   initial_index = 0;
  83.  
  84.   va_start (args, menu_only);
  85.   label = va_arg (args, const gchar *);
  86.  
  87.   for (i = 0; label; i++)
  88.     {
  89.       callback   = va_arg (args, GtkSignalFunc);
  90.       data       = va_arg (args, gpointer);
  91.       user_data  = va_arg (args, gpointer);
  92.       widget_ptr = va_arg (args, GtkWidget **);
  93.       active     = va_arg (args, gboolean);
  94.  
  95.       if (strcmp (label, "---"))
  96.     {
  97.       menuitem = gtk_menu_item_new_with_label (label);
  98.  
  99.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  100.                   callback,
  101.                   data);
  102.  
  103.       if (user_data)
  104.         gtk_object_set_user_data (GTK_OBJECT (menuitem), user_data);
  105.     }
  106.       else
  107.     {
  108.       menuitem = gtk_menu_item_new ();
  109.  
  110.       gtk_widget_set_sensitive (menuitem, FALSE);
  111.     }
  112.  
  113.       gtk_menu_append (GTK_MENU (menu), menuitem);
  114.  
  115.       if (widget_ptr)
  116.     *widget_ptr = menuitem;
  117.  
  118.       gtk_widget_show (menuitem);
  119.  
  120.       /*  remember the initial menu item  */
  121.       if (active)
  122.     initial_index = i;
  123.  
  124.       label = va_arg (args, const gchar *);
  125.     }
  126.   va_end (args);
  127.  
  128.   if (! menu_only)
  129.     {
  130.       GtkWidget *optionmenu;
  131.  
  132.       optionmenu = gtk_option_menu_new ();
  133.       gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
  134.  
  135.       /*  select the initial menu item  */
  136.       gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), initial_index);
  137.  
  138.       return optionmenu;
  139.     }
  140.  
  141.   return menu;
  142. }
  143.  
  144. /**
  145.  * gimp_option_menu_new2:
  146.  * @menu_only:          #TRUE if the function should return a #GtkMenu only.
  147.  * @menu_item_callback: The callback each menu item's "activate" signal will
  148.  *                      be connected with.
  149.  * @data:               The data which will be passed to gtk_signal_connect().
  150.  * @initial:            The @user_data of the initially selected menu item.
  151.  * @...:                A #NULL terminated @va_list describing the menu items.
  152.  *
  153.  * Returns: A #GtkOptionMenu or a #GtkMenu (depending on @menu_only).
  154.  **/
  155. GtkWidget *
  156. gimp_option_menu_new2 (gboolean         menu_only,
  157.                GtkSignalFunc    menu_item_callback,
  158.                gpointer         data,
  159.                gpointer         initial, /* user_data */
  160.  
  161.                /* specify menu items as va_list:
  162.             *  const gchar *label,
  163.             *  gpointer     user_data,
  164.             *  GtkWidget  **widget_ptr,
  165.             */
  166.  
  167.                ...)
  168. {
  169.   GtkWidget *menu;
  170.   GtkWidget *menuitem;
  171.  
  172.   /*  menu item variables  */
  173.   const gchar  *label;
  174.   gpointer      user_data;
  175.   GtkWidget   **widget_ptr;
  176.  
  177.   va_list args;
  178.   gint    i;
  179.   gint    initial_index;
  180.  
  181.   menu = gtk_menu_new ();
  182.  
  183.   /*  create the menu items  */
  184.   initial_index = 0;
  185.  
  186.   va_start (args, initial);
  187.   label = va_arg (args, const gchar *);
  188.  
  189.   for (i = 0; label; i++)
  190.     {
  191.       user_data  = va_arg (args, gpointer);
  192.       widget_ptr = va_arg (args, GtkWidget **);
  193.  
  194.       if (strcmp (label, "---"))
  195.     {
  196.       menuitem = gtk_menu_item_new_with_label (label);
  197.  
  198.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  199.                   menu_item_callback,
  200.                   data);
  201.  
  202.       if (user_data)
  203.         gtk_object_set_user_data (GTK_OBJECT (menuitem), user_data);
  204.     }
  205.       else
  206.     {
  207.       menuitem = gtk_menu_item_new ();
  208.  
  209.       gtk_widget_set_sensitive (menuitem, FALSE);
  210.     }
  211.  
  212.       gtk_menu_append (GTK_MENU (menu), menuitem);
  213.  
  214.       if (widget_ptr)
  215.     *widget_ptr = menuitem;
  216.  
  217.       gtk_widget_show (menuitem);
  218.  
  219.       /*  remember the initial menu item  */
  220.       if (user_data == initial)
  221.     initial_index = i;
  222.  
  223.       label = va_arg (args, const gchar *);
  224.     }
  225.   va_end (args);
  226.  
  227.   if (! menu_only)
  228.     {
  229.       GtkWidget *optionmenu;
  230.  
  231.       optionmenu = gtk_option_menu_new ();
  232.       gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
  233.  
  234.       /*  select the initial menu item  */
  235.       gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), initial_index);
  236.  
  237.       return optionmenu;
  238.     }
  239.  
  240.   return menu;
  241. }
  242.  
  243. /**
  244.  * gimp_option_menu_set_history:
  245.  * @option_menu: A #GtkOptionMenu as returned by gimp_option_menu_new() or
  246.  *               gimp_option_menu_new2().
  247.  * @user_data:   The @user_data of the menu item you want to select.
  248.  **/
  249. void
  250. gimp_option_menu_set_history (GtkOptionMenu *option_menu,
  251.                   gpointer       user_data)
  252. {
  253.   GtkWidget *menu_item;
  254.   GList     *list;
  255.   gint       history = 0;
  256.  
  257.   g_return_if_fail (option_menu);
  258.   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
  259.  
  260.   for (list = GTK_MENU_SHELL (option_menu->menu)->children;
  261.        list;
  262.        list = g_list_next (list))
  263.     {
  264.       menu_item = GTK_WIDGET (list->data);
  265.  
  266.       if (GTK_IS_LABEL (GTK_BIN (menu_item)->child) &&
  267.       gtk_object_get_user_data (GTK_OBJECT (menu_item)) == user_data)
  268.     {
  269.       break;
  270.     }
  271.  
  272.       history++;
  273.     }
  274.  
  275.   if (list)
  276.     gtk_option_menu_set_history (option_menu, history);
  277. }
  278.  
  279. /**
  280.  * gimp_radio_group_new:
  281.  * @in_frame:    #TRUE if you want a #GtkFrame around the radio button group.
  282.  * @frame_title: The title of the Frame or #NULL if you don't want a title.
  283.  * @...:         A #NULL terminated @va_list describing the radio buttons.
  284.  *
  285.  * Returns: A #GtkFrame or #GtkVbox (depending on @in_frame).
  286.  **/
  287. GtkWidget *
  288. gimp_radio_group_new (gboolean            in_frame,
  289.               const gchar        *frame_title,
  290.  
  291.               /* specify radio buttons as va_list:
  292.                *  const gchar    *label,
  293.                *  GtkSignalFunc   callback,
  294.                *  gpointer        data,
  295.                *  gpointer        user_data,
  296.                *  GtkWidget     **widget_ptr,
  297.                *  gboolean        active,
  298.                */
  299.  
  300.               ...)
  301. {
  302.   GtkWidget *vbox;
  303.   GtkWidget *button;
  304.   GSList    *group;
  305.  
  306.   /*  radio button variables  */
  307.   const gchar    *label;
  308.   GtkSignalFunc   callback;
  309.   gpointer        data;
  310.   gpointer        user_data;
  311.   GtkWidget     **widget_ptr;
  312.   gboolean        active;
  313.  
  314.   va_list args;
  315.  
  316.   vbox = gtk_vbox_new (FALSE, 1);
  317.  
  318.   group = NULL;
  319.  
  320.   /*  create the radio buttons  */
  321.   va_start (args, frame_title);
  322.   label = va_arg (args, const gchar *);
  323.   while (label)
  324.     {
  325.       callback   = va_arg (args, GtkSignalFunc);
  326.       data       = va_arg (args, gpointer);
  327.       user_data  = va_arg (args, gpointer);
  328.       widget_ptr = va_arg (args, GtkWidget **);
  329.       active     = va_arg (args, gboolean);
  330.  
  331.       if (label != (gpointer) 1)
  332.     button = gtk_radio_button_new_with_label (group, label);
  333.       else
  334.     button = gtk_radio_button_new (group);
  335.  
  336.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  337.       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  338.  
  339.       if (user_data)
  340.     gtk_object_set_user_data (GTK_OBJECT (button), user_data);
  341.  
  342.       if (widget_ptr)
  343.     *widget_ptr = button;
  344.  
  345.       if (active)
  346.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  347.  
  348.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  349.               callback,
  350.               data);
  351.  
  352.       gtk_widget_show (button);
  353.  
  354.       label = va_arg (args, const gchar *);
  355.     }
  356.   va_end (args);
  357.  
  358.   if (in_frame)
  359.     {
  360.       GtkWidget *frame;
  361.  
  362.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  363.  
  364.       frame = gtk_frame_new (frame_title);
  365.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  366.       gtk_widget_show (vbox);
  367.  
  368.       return frame;
  369.     }
  370.  
  371.   return vbox;
  372. }
  373.  
  374. /**
  375.  * gimp_radio_group_new2:
  376.  * @in_frame:              #TRUE if you want a #GtkFrame around the
  377.  *                         radio button group.
  378.  * @frame_title:           The title of the Frame or #NULL if you don't want
  379.  *                         a title.
  380.  * @radio_button_callback: The callback each button's "toggled" signal will
  381.  *                         be connected with.
  382.  * @data:                  The data which will be passed to
  383.  *                         gtk_signal_connect().
  384.  * @initial:               The @user_data of the initially pressed radio button.
  385.  * @...:                   A #NULL terminated @va_list describing
  386.  *                         the radio buttons.
  387.  *
  388.  * Returns: A #GtkFrame or #GtkVbox (depending on @in_frame).
  389.  **/
  390. GtkWidget *
  391. gimp_radio_group_new2 (gboolean         in_frame,
  392.                const gchar     *frame_title,
  393.                GtkSignalFunc    radio_button_callback,
  394.                gpointer         data,
  395.                gpointer         initial, /* user_data */
  396.  
  397.                /* specify radio buttons as va_list:
  398.             *  const gchar *label,
  399.             *  gpointer     user_data,
  400.             *  GtkWidget  **widget_ptr,
  401.             */
  402.  
  403.                ...)
  404. {
  405.   GtkWidget *vbox;
  406.   GtkWidget *button;
  407.   GSList    *group;
  408.  
  409.   /*  radio button variables  */
  410.   const gchar *label;
  411.   gpointer     user_data;
  412.   GtkWidget  **widget_ptr;
  413.  
  414.   va_list args;
  415.  
  416.   vbox = gtk_vbox_new (FALSE, 1);
  417.  
  418.   group = NULL;
  419.  
  420.   /*  create the radio buttons  */
  421.   va_start (args, initial);
  422.   label = va_arg (args, const gchar *);
  423.  
  424.   while (label)
  425.     {
  426.       user_data  = va_arg (args, gpointer);
  427.       widget_ptr = va_arg (args, GtkWidget **);
  428.  
  429.       if (label != (gpointer) 1)
  430.     button = gtk_radio_button_new_with_label (group, label);
  431.       else
  432.     button = gtk_radio_button_new (group);
  433.  
  434.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  435.       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  436.  
  437.       if (user_data)
  438.     gtk_object_set_user_data (GTK_OBJECT (button), user_data);
  439.  
  440.       if (widget_ptr)
  441.     *widget_ptr = button;
  442.  
  443.       if (initial == user_data)
  444.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  445.  
  446.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  447.               radio_button_callback,
  448.               data);
  449.  
  450.       gtk_widget_show (button);
  451.  
  452.       label = va_arg (args, const gchar *);
  453.     }
  454.   va_end (args);
  455.  
  456.   if (in_frame)
  457.     {
  458.       GtkWidget *frame;
  459.  
  460.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  461.  
  462.       frame = gtk_frame_new (frame_title);
  463.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  464.       gtk_widget_show (vbox);
  465.  
  466.       return frame;
  467.     }
  468.  
  469.   return vbox;
  470. }
  471.  
  472. /**
  473.  * gimp_spin_button_new:
  474.  * @adjustment:     Returns the spinbutton's #GtkAdjustment.
  475.  * @value:          The initial value of the spinbutton.
  476.  * @lower:          The lower boundary.
  477.  * @upper:          The uppper boundary.
  478.  * @step_increment: The spinbutton's step increment.
  479.  * @page_increment: The spinbutton's page increment (mouse button 2).
  480.  * @page_size:      The spinbutton's page size.
  481.  * @climb_rate:     The spinbutton's climb rate.
  482.  * @digits:         The spinbutton's number of decimal digits.
  483.  *
  484.  * This function is a shortcut for gtk_adjustment_new() and a subsequent
  485.  * gtk_spin_button_new() and does some more initialisation stuff like
  486.  * setting a standard minimun horizontal size.
  487.  *
  488.  * Returns: A #GtkSpinbutton and it's #GtkAdjustment.
  489.  **/
  490. GtkWidget *
  491. gimp_spin_button_new (GtkObject **adjustment,  /* return value */
  492.               gfloat      value,
  493.               gfloat      lower,
  494.               gfloat      upper,
  495.               gfloat      step_increment,
  496.               gfloat      page_increment,
  497.               gfloat      page_size,
  498.               gfloat      climb_rate,
  499.               guint       digits)
  500. {
  501.   GtkWidget *spinbutton;
  502.  
  503.   *adjustment = gtk_adjustment_new (value, lower, upper,
  504.                     step_increment, page_increment, page_size);
  505.  
  506.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (*adjustment),
  507.                     climb_rate, digits);
  508.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  509.                    GTK_SHADOW_NONE);
  510.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  511.   gtk_widget_set_usize (spinbutton, 75, -1);
  512.  
  513.   return spinbutton;
  514. }
  515.  
  516. static void
  517. gimp_scale_entry_unconstrained_adjustment_callback (GtkAdjustment *adjustment,
  518.                             GtkAdjustment *other_adj)
  519. {
  520.   gtk_signal_handler_block_by_data (GTK_OBJECT (other_adj), adjustment);
  521.  
  522.   gtk_adjustment_set_value (other_adj, adjustment->value);
  523.  
  524.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (other_adj), adjustment);
  525. }
  526.  
  527. /**
  528.  * gimp_scale_entry_new:
  529.  * @table:               The #GtkTable the widgets will be attached to.
  530.  * @column:              The column to start with.
  531.  * @row:                 The row to attach the widgets.
  532.  * @text:                The text for the #GtkLabel which will appear
  533.  *                       left of the #GtkHScale.
  534.  * @scale_usize:         The minimum horizontal size of the #GtkHScale.
  535.  * @spinbutton_usize:    The minimum horizontal size of the #GtkSpinButton.
  536.  * @value:               The initial value.
  537.  * @lower:               The lower boundary.
  538.  * @upper:               The upper boundary.
  539.  * @step_increment:      The step increment.
  540.  * @page_increment:      The page increment.
  541.  * @digits:              The number of decimal digits.
  542.  * @constrain:           #TRUE if the range of possible values of the
  543.  *                       #GtkSpinButton should be the same as of the #GtkHScale.
  544.  * @unconstrained_lower: The spinbutton's lower boundary
  545.  *                       if @constrain == #FALSE.
  546.  * @unconstrained_upper: The spinbutton's upper boundary
  547.  *                       if @constrain == #FALSE.
  548.  * @tooltip:             A tooltip message for the scale and the spinbutton.
  549.  * @help_data:           The widgets' help_data (see gimp_help_set_help_data()).
  550.  *
  551.  * This function creates a #GtkLabel, a #GtkHScale and a #GtkSpinButton and
  552.  * attaches them to a 3-column #GtkTable.
  553.  *
  554.  * Note that if you pass a @tooltip or @help_data to this function you'll
  555.  * have to initialize GIMP's help system with gimp_help_init() before using it.
  556.  *
  557.  * Returns: The #GtkSpinButton's #GtkAdjustment.
  558.  **/
  559. GtkObject *
  560. gimp_scale_entry_new (GtkTable    *table,
  561.               gint         column,
  562.               gint         row,
  563.               const gchar *text,
  564.               gint         scale_usize,
  565.               gint         spinbutton_usize,
  566.               gfloat       value,
  567.               gfloat       lower,
  568.               gfloat       upper,
  569.               gfloat       step_increment,
  570.               gfloat       page_increment,
  571.               guint        digits,
  572.               gboolean     constrain,
  573.               gfloat       unconstrained_lower,
  574.               gfloat       unconstrained_upper,
  575.               const gchar *tooltip,
  576.               const gchar *help_data)
  577. {
  578.   GtkWidget *label;
  579.   GtkWidget *scale;
  580.   GtkWidget *spinbutton;
  581.   GtkObject *adjustment;
  582.   GtkObject *return_adj;
  583.  
  584.   label = gtk_label_new (text);
  585.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  586.   gtk_table_attach (GTK_TABLE (table), label,
  587.                     column, column + 1, row, row + 1,
  588.                     GTK_FILL, GTK_FILL, 0, 0);
  589.   gtk_widget_show (label);
  590.  
  591.   if (! constrain &&
  592.       unconstrained_lower <= lower &&
  593.       unconstrained_upper >= upper)
  594.     {
  595.       GtkObject *constrained_adj;
  596.  
  597.       constrained_adj = gtk_adjustment_new (value, lower, upper,
  598.                         step_increment, page_increment,
  599.                         0.0);
  600.  
  601.       spinbutton = gimp_spin_button_new (&adjustment, value,
  602.                      unconstrained_lower,
  603.                      unconstrained_upper,
  604.                      step_increment, page_increment, 0.0,
  605.                      1.0, digits);
  606.  
  607.       gtk_signal_connect
  608.     (GTK_OBJECT (constrained_adj), "value_changed",
  609.      GTK_SIGNAL_FUNC (gimp_scale_entry_unconstrained_adjustment_callback),
  610.      adjustment);
  611.  
  612.       gtk_signal_connect
  613.     (GTK_OBJECT (adjustment), "value_changed",
  614.      GTK_SIGNAL_FUNC (gimp_scale_entry_unconstrained_adjustment_callback),
  615.      constrained_adj);
  616.  
  617.       return_adj = adjustment;
  618.  
  619.       adjustment = constrained_adj;
  620.     }
  621.   else
  622.     {
  623.       spinbutton = gimp_spin_button_new (&adjustment, value, lower, upper,
  624.                      step_increment, page_increment, 0.0,
  625.                      1.0, digits);
  626.  
  627.       return_adj = adjustment;
  628.     }
  629.     
  630.   if (spinbutton_usize > 0)
  631.     gtk_widget_set_usize (spinbutton, spinbutton_usize, -1);
  632.  
  633.   scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
  634.   if (scale_usize > 0)
  635.     gtk_widget_set_usize (scale, scale_usize, -1);
  636.   gtk_scale_set_digits (GTK_SCALE (scale), digits);
  637.   gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
  638.   gtk_table_attach (GTK_TABLE (table), scale,
  639.             column + 1, column + 2, row, row + 1,
  640.             GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
  641.   gtk_widget_show (scale);
  642.  
  643.   gtk_table_attach (GTK_TABLE (table), spinbutton,
  644.             column + 2, column + 3, row, row + 1,
  645.             GTK_SHRINK, GTK_SHRINK, 0, 0);
  646.   gtk_widget_show (spinbutton);
  647.  
  648.   if (tooltip || help_data)
  649.     {
  650.       gimp_help_set_help_data (scale, tooltip, help_data);
  651.       gimp_help_set_help_data (spinbutton, tooltip, help_data);
  652.     }
  653.  
  654.   gtk_object_set_data (GTK_OBJECT (return_adj), "label", label);
  655.   gtk_object_set_data (GTK_OBJECT (return_adj), "scale", scale);
  656.   gtk_object_set_data (GTK_OBJECT (return_adj), "spinbutton", spinbutton);
  657.  
  658.   return return_adj;
  659. }
  660.  
  661. static void
  662. gimp_random_seed_toggle_update (GtkWidget *widget,
  663.                 gpointer   data)
  664. {
  665.   gint *toggle_val;
  666.  
  667.   toggle_val = (gint *) data;
  668.  
  669.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  670.     *toggle_val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget),
  671.                             "time_true"));
  672.   else
  673.     *toggle_val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget),
  674.                             "time_false"));
  675.  
  676.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  677. }
  678.  
  679. /**
  680.  * gimp_random_seed_new:
  681.  * @seed:       A pointer to the variable which stores the random seed.
  682.  * @use_time:   A pointer to the variable which stores the @use_time
  683.  *              toggle boolean.
  684.  * @time_true:  The value to write to @use_time if the toggle button is checked.
  685.  * @time_false: The value to write to @use_time if the toggle button is
  686.  *              unchecked.
  687.  *
  688.  * Note that this widget automatically sets tooltips with
  689.  * gimp_help_set_help_data(), so you'll have to initialize GIMP's help
  690.  * system with gimp_help_init() before using it.
  691.  *
  692.  * Returns: A #GtkHBox containing a #GtkSpinButton for the random seed and
  693.  *          a #GtkToggleButton for toggling the @use_time behaviour.
  694.  **/
  695. GtkWidget *
  696. gimp_random_seed_new (gint       *seed,
  697.               gint       *use_time,
  698.               gint        time_true,
  699.               gint        time_false)
  700. {
  701.   GtkWidget *hbox;
  702.   GtkWidget *spinbutton;
  703.   GtkObject *adj;
  704.   GtkWidget *button;
  705.  
  706.   hbox = gtk_hbox_new (FALSE, 4);
  707.  
  708.   spinbutton = gimp_spin_button_new (&adj, *seed,
  709.                                      0, G_MAXRAND, 1, 10, 0, 1, 0);
  710.   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
  711.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  712.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  713.                       seed);
  714.   gtk_widget_show (spinbutton);
  715.  
  716.   gimp_help_set_help_data (spinbutton,
  717.                            _("If the \"Time\" button is not pressed, "
  718.                              "use this value for random number generator "
  719.                              "seed - this allows you to repeat a "
  720.                              "given \"random\" operation"), NULL);
  721.  
  722.   button = gtk_toggle_button_new_with_label (_("Time"));
  723.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  724.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  725.                       GTK_SIGNAL_FUNC (gimp_random_seed_toggle_update),
  726.                       use_time);
  727.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  728.   gtk_widget_show (button);
  729.  
  730.   gimp_help_set_help_data (button,
  731.                            _("Seed random number generator from the current "
  732.                              "time - this guarantees a reasonable "
  733.                              "randomization"), NULL);
  734.  
  735.   gtk_object_set_data (GTK_OBJECT (button), "time_true",
  736.                GINT_TO_POINTER (time_true));
  737.   gtk_object_set_data (GTK_OBJECT (button), "time_false",
  738.                GINT_TO_POINTER (time_false));
  739.  
  740.   gtk_object_set_data (GTK_OBJECT (button), "inverse_sensitive",
  741.                spinbutton);
  742.  
  743.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  744.                                 *use_time == time_true);
  745.  
  746.   gtk_object_set_data (GTK_OBJECT (hbox), "spinbutton", spinbutton);
  747.   gtk_object_set_data (GTK_OBJECT (hbox), "togglebutton", button);
  748.  
  749.   return hbox;
  750. }
  751.  
  752. typedef struct
  753. {
  754.   GimpChainButton *chainbutton;
  755.   gboolean         chain_constrains_ratio;
  756.   gdouble          orig_x;
  757.   gdouble          orig_y;
  758.   gdouble          last_x;
  759.   gdouble          last_y;
  760. } GimpCoordinatesData;
  761.  
  762. static void
  763. gimp_coordinates_callback (GtkWidget *widget,
  764.                gpointer   data)
  765. {
  766.   GimpCoordinatesData *gcd;
  767.   gdouble new_x;
  768.   gdouble new_y;
  769.  
  770.   gcd = (GimpCoordinatesData *) data;
  771.  
  772.   new_x = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 0);
  773.   new_y = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 1);
  774.  
  775.   if (gimp_chain_button_get_active (gcd->chainbutton))
  776.     {
  777.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "value_changed");
  778.  
  779.       if (gcd->chain_constrains_ratio)
  780.     {
  781.       if ((gcd->orig_x != 0) && (gcd->orig_y != 0))
  782.         {
  783.           if (new_x != gcd->last_x)
  784.         {
  785.           gcd->last_x = new_x;
  786.           gcd->last_y = new_y = (new_x * gcd->orig_y) / gcd->orig_x;
  787.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 1,
  788.                           new_y);
  789.         }
  790.           else if (new_y != gcd->last_y)
  791.         {
  792.           gcd->last_y = new_y;
  793.           gcd->last_x = new_x = (new_y * gcd->orig_x) / gcd->orig_y;
  794.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 0,
  795.                           new_x);
  796.         }
  797.         }
  798.     }
  799.       else
  800.     {
  801.       if (new_x != gcd->last_x)
  802.         {
  803.           gcd->last_y = new_y = gcd->last_x = new_x;
  804.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 1, new_x);
  805.         }
  806.       else if (new_y != gcd->last_y)
  807.         {
  808.           gcd->last_x = new_x = gcd->last_y = new_y;
  809.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 0, new_y);
  810.         }
  811.     }
  812.     }
  813.   else
  814.     {
  815.       if (new_x != gcd->last_x)
  816.         gcd->last_x = new_x;
  817.       if (new_y != gcd->last_y)
  818.         gcd->last_y = new_y;
  819.     }     
  820. }
  821.  
  822. /**
  823.  * gimp_coordinates_new:
  824.  * @unit:                   The initial unit of the #GimpUnitMenu.
  825.  * @unit_format:            The unit format string as passed to
  826.  *                          gimp_size_entry_new().
  827.  * @menu_show_pixels:       #TRUE if the #GimpUnitMenu should contain an item for
  828.  *                          GIMP_UNIT_PIXEL.
  829.  * @menu_show_percent:      #TRUE if the #GimpUnitMenu should contain an item for
  830.  *                          GIMP_UNIT_PERCENT.
  831.  * @spinbutton_usize:       The horizontal usize of the #GimpSizeEntry's
  832.  *                           #GtkSpinButton's.
  833.  * @update_policy:          The update policy for the #GimpSizeEntry.
  834.  * @chainbutton_active:     #TRUE if the attached #GimpChainButton should be
  835.  *                          active.
  836.  * @chain_constrains_ratio: #TRUE if the chainbutton should constrain the
  837.  *                          fields' aspect ratio. If #FALSE, the values will
  838.  *                          be constrained.
  839.  * @xlabel:                 The label for the X coordinate.
  840.  * @x:                      The initial value of the X coordinate.
  841.  * @xres:                   The horizontal resolution in DPI.
  842.  * @lower_boundary_x:       The lower boundary of the X coordinate.
  843.  * @upper_boundary_x:       The upper boundary of the X coordinate.
  844.  * @xsize_0:                The X value which will be treated as 0%.
  845.  * @xsize_100:              The X value which will be treated as 100%.
  846.  * @ylabel:                 The label for the Y coordinate.
  847.  * @y:                      The initial value of the Y coordinate.
  848.  * @yres:                   The vertical resolution in DPI.
  849.  * @lower_boundary_y:       The lower boundary of the Y coordinate.
  850.  * @upper_boundary_y:       The upper boundary of the Y coordinate.
  851.  * @ysize_0:                The Y value which will be treated as 0%.
  852.  * @ysize_100:              The Y value which will be treated as 100%.
  853.  *
  854.  * Returns: A #GimpSizeEntry with two fields for x/y coordinates/sizes with
  855.  *          a #GimpChainButton attached to constrain either the two fields'
  856.  *          values or the ratio between them.
  857.  **/
  858. GtkWidget *
  859. gimp_coordinates_new (GimpUnit         unit,
  860.               const gchar     *unit_format,
  861.               gboolean         menu_show_pixels,
  862.               gboolean         menu_show_percent,
  863.               gint             spinbutton_usize,
  864.               GimpSizeEntryUpdatePolicy  update_policy,
  865.  
  866.               gboolean         chainbutton_active,
  867.               gboolean         chain_constrains_ratio,
  868.  
  869.               const gchar     *xlabel,
  870.               gdouble          x,
  871.               gdouble          xres,
  872.               gdouble          lower_boundary_x,
  873.               gdouble          upper_boundary_x,
  874.               gdouble          xsize_0,   /* % */
  875.               gdouble          xsize_100, /* % */
  876.  
  877.               const gchar     *ylabel,
  878.               gdouble          y,
  879.               gdouble          yres,
  880.               gdouble          lower_boundary_y,
  881.               gdouble          upper_boundary_y,
  882.               gdouble          ysize_0,   /* % */
  883.               gdouble          ysize_100  /* % */)
  884. {
  885.   GimpCoordinatesData *gcd;
  886.   GtkObject *adjustment;
  887.   GtkWidget *spinbutton;
  888.   GtkWidget *sizeentry;
  889.   GtkWidget *chainbutton;
  890.  
  891.   spinbutton = gimp_spin_button_new (&adjustment, 1, 0, 1, 1, 10, 1, 1, 2);
  892.   sizeentry = gimp_size_entry_new (1, unit, unit_format,
  893.                    menu_show_pixels,
  894.                    menu_show_percent,
  895.                    FALSE,
  896.                    spinbutton_usize,
  897.                    update_policy);
  898.   gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 0, 4);  
  899.   gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 2, 4);  
  900.   gimp_size_entry_add_field (GIMP_SIZE_ENTRY (sizeentry),
  901.                              GTK_SPIN_BUTTON (spinbutton), NULL);
  902.   gtk_table_attach_defaults (GTK_TABLE (sizeentry), spinbutton, 1, 2, 0, 1);
  903.   gtk_widget_show (spinbutton);
  904.  
  905.   gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry),
  906.                 (update_policy == GIMP_SIZE_ENTRY_UPDATE_RESOLUTION) || (menu_show_pixels == FALSE) ?
  907.                 GIMP_UNIT_INCH : GIMP_UNIT_PIXEL);
  908.  
  909.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 0, xres, TRUE);
  910.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 1, yres, TRUE);
  911.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 0,
  912.                      lower_boundary_x, upper_boundary_x);
  913.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 1,
  914.                      lower_boundary_y, upper_boundary_y);
  915.  
  916.   if (menu_show_percent)
  917.     {
  918.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 0,
  919.                 xsize_0, xsize_100);
  920.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 1,
  921.                 ysize_0, ysize_100);
  922.     }
  923.  
  924.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 0, x);
  925.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 1, y);
  926.  
  927.   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), xlabel, 0, 0, 1.0);
  928.   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), ylabel, 1, 0, 1.0);
  929.  
  930.   chainbutton = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
  931.   if (chainbutton_active)
  932.     gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (chainbutton), TRUE);
  933.   gtk_table_attach (GTK_TABLE (sizeentry), chainbutton, 2, 3, 0, 2,
  934.             GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  935.   gtk_widget_show (chainbutton);
  936.  
  937.   gcd = g_new (GimpCoordinatesData, 1);
  938.   gcd->chainbutton            = GIMP_CHAIN_BUTTON (chainbutton);
  939.   gcd->chain_constrains_ratio = chain_constrains_ratio;
  940.   gcd->orig_x                 = x;
  941.   gcd->orig_y                 = y;
  942.   gcd->last_x                 = x;
  943.   gcd->last_y                 = y;
  944.  
  945.   gtk_signal_connect_object (GTK_OBJECT (sizeentry), "destroy",
  946.                  GTK_SIGNAL_FUNC (g_free),
  947.                  (GtkObject *) gcd);
  948.  
  949.   gtk_signal_connect (GTK_OBJECT (sizeentry), "value_changed", 
  950.                       GTK_SIGNAL_FUNC (gimp_coordinates_callback),
  951.                       gcd);
  952.  
  953.   gtk_object_set_data (GTK_OBJECT (sizeentry), "chainbutton", chainbutton);
  954.  
  955.   return sizeentry;
  956. }
  957.  
  958. typedef struct
  959. {
  960.   GtkAdjustment *adjustment;
  961.   GtkAdjustment *divided_adj;
  962.   guint          mem_size_unit;
  963. } GimpMemSizeEntryData;
  964.  
  965. static void
  966. gimp_mem_size_entry_callback (GtkAdjustment *adj,
  967.                   gpointer       data)
  968. {
  969.   GimpMemSizeEntryData *gmsed;
  970.   guint new_value;
  971.  
  972.   gmsed = (GimpMemSizeEntryData *)data;
  973.   new_value = adj->value * gmsed->mem_size_unit;
  974.  
  975.   gtk_adjustment_set_value (gmsed->adjustment, new_value);
  976. }
  977.  
  978. static void
  979. gimp_mem_size_unit_callback (GtkWidget *widget,
  980.                  gpointer   data)
  981. {
  982.   GimpMemSizeEntryData *gmsed;
  983.   guint divided_mem_size;
  984.   guint new_unit;
  985.  
  986.   gmsed = (GimpMemSizeEntryData *)data;
  987.  
  988.   new_unit = GPOINTER_TO_UINT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  989.  
  990.   if (new_unit && new_unit != gmsed->mem_size_unit)
  991.     {
  992.       divided_mem_size = gmsed->adjustment->value / new_unit;
  993.       gmsed->mem_size_unit = new_unit;
  994.  
  995.       gtk_adjustment_set_value (GTK_ADJUSTMENT (gmsed->divided_adj), 
  996.                 divided_mem_size);
  997.     }
  998. }
  999.  
  1000. /**
  1001.  * gimp_mem_size_entry_new:
  1002.  * @adjustment: The adjustment containing the memsize and it's limits.
  1003.  *
  1004.  * Returns: A #GtkHBox with a #GtkSpinButton and a #GtkOptionMenu.
  1005.  **/
  1006. GtkWidget *
  1007. gimp_mem_size_entry_new (GtkAdjustment *adjustment)
  1008. {
  1009.   GtkWidget *hbox;
  1010.   GtkObject *divided_adj;
  1011.   GtkWidget *spinbutton;
  1012.   GtkWidget *optionmenu;
  1013.  
  1014.   GimpMemSizeEntryData *gmsed;
  1015.   guint mem_size_unit = 1;
  1016.   guint divided_mem_size;  
  1017.   gint  i;
  1018.  
  1019.   gmsed = g_new (GimpMemSizeEntryData, 1);
  1020.  
  1021.   for (i = 0; i < 2; i++)
  1022.     {
  1023.       if ( (gint) adjustment->value % (mem_size_unit * 1024) != 0 )
  1024.     break;
  1025.       mem_size_unit *= 1024;
  1026.     }
  1027.   divided_mem_size =  adjustment->value / mem_size_unit;
  1028.  
  1029.   hbox = gtk_hbox_new (FALSE, 2);
  1030.   spinbutton =
  1031.     gimp_spin_button_new (÷d_adj, divided_mem_size,
  1032.               0.0, (4096.0 * 1024 * 1024 - 1), 1.0, 16.0, 0.0,
  1033.               1.0, 0.0);
  1034.   gtk_signal_connect (GTK_OBJECT (divided_adj), "value_changed",
  1035.               GTK_SIGNAL_FUNC (gimp_mem_size_entry_callback),
  1036.               gmsed);
  1037.   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
  1038.   gtk_widget_show (spinbutton);
  1039.  
  1040.   optionmenu =
  1041.     gimp_option_menu_new2 (FALSE, gimp_mem_size_unit_callback,
  1042.                gmsed, GUINT_TO_POINTER (mem_size_unit),
  1043.  
  1044.                _("Bytes"),     GINT_TO_POINTER (1), NULL,
  1045.                _("KiloBytes"), GINT_TO_POINTER (1024), NULL,
  1046.                _("MegaBytes"), GINT_TO_POINTER (1024 * 1024), NULL,
  1047.  
  1048.                NULL);
  1049.   gtk_box_pack_start (GTK_BOX (hbox), optionmenu, FALSE, FALSE, 0);
  1050.   gtk_widget_show (optionmenu);
  1051.  
  1052.   gtk_signal_connect_object (GTK_OBJECT (hbox), "destroy",
  1053.                  GTK_SIGNAL_FUNC (gtk_object_unref),
  1054.                  GTK_OBJECT (adjustment));
  1055.   gtk_signal_connect_object (GTK_OBJECT (hbox), "destroy",
  1056.                  GTK_SIGNAL_FUNC (g_free),
  1057.                  (GtkObject *) gmsed);
  1058.  
  1059.   gmsed->adjustment = adjustment;
  1060.   gmsed->divided_adj = GTK_ADJUSTMENT (divided_adj);
  1061.   gmsed->mem_size_unit = mem_size_unit;
  1062.  
  1063.   gtk_object_set_data (GTK_OBJECT (hbox), "spinbutton", spinbutton);
  1064.   gtk_object_set_data (GTK_OBJECT (hbox), "optionmenu", optionmenu);
  1065.  
  1066.   return hbox;
  1067. }
  1068.  
  1069. /**
  1070.  * gimp_pixmap_button_new:
  1071.  * @xpm_data: The XPM data which will be passed to gimp_pixmap_new().
  1072.  * @text:     An optional text which will appear right of the pixmap.
  1073.  *
  1074.  * Returns: A #GtkButton with a #GimpPixmap and an optional #GtkLabel.
  1075.  **/
  1076. GtkWidget *
  1077. gimp_pixmap_button_new (gchar       **xpm_data,
  1078.             const gchar  *text)
  1079. {
  1080.   GtkWidget *button;
  1081.   GtkWidget *pixmap;
  1082.  
  1083.   button = gtk_button_new ();
  1084.   pixmap = gimp_pixmap_new (xpm_data);
  1085.  
  1086.   if (text)
  1087.     {
  1088.       GtkWidget *abox;
  1089.       GtkWidget *hbox;
  1090.       GtkWidget *label;
  1091.  
  1092.       abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1093.       gtk_container_add (GTK_CONTAINER (button), abox);
  1094.       gtk_widget_show (abox);
  1095.  
  1096.       hbox = gtk_hbox_new (FALSE, 0);
  1097.       gtk_container_add (GTK_CONTAINER (abox), hbox);
  1098.       gtk_widget_show (hbox);
  1099.  
  1100.       gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 4);
  1101.       gtk_widget_show (pixmap);
  1102.  
  1103.       label = gtk_label_new (text);
  1104.       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
  1105.       gtk_widget_show (label);
  1106.     }
  1107.   else
  1108.     {
  1109.       gtk_container_add (GTK_CONTAINER (button), pixmap);
  1110.       gtk_widget_show (pixmap);
  1111.     }
  1112.  
  1113.  
  1114.   return button;
  1115. }
  1116.  
  1117. /*
  1118.  *  Standard Callbacks
  1119.  */
  1120.  
  1121. /**
  1122.  * gimp_toggle_button_sensitive_update:
  1123.  * @toggle_button: The #GtkToggleButton the "set_sensitive" and
  1124.  *                 "inverse_sensitive" lists are attached to.
  1125.  *
  1126.  * If you attached a pointer to a #GtkWidget with gtk_object_set_data() and
  1127.  * the "set_sensitive" key to the #GtkToggleButton, the sensitive state of
  1128.  * the attached widget will be set according to the toggle button's
  1129.  * "active" state.
  1130.  *
  1131.  * You can attach an arbitrary list of widgets by attaching another
  1132.  * "set_sensitive" data pointer to the first widget (and so on...).
  1133.  *
  1134.  * This function can also set the sensitive state according to the toggle
  1135.  * button's inverse "active" state by attaching widgets with the
  1136.  * "inverse_sensitive" key.
  1137.  **/
  1138. void
  1139. gimp_toggle_button_sensitive_update (GtkToggleButton *toggle_button)
  1140. {
  1141.   GtkWidget *set_sensitive;
  1142.   gboolean   active;
  1143.  
  1144.   active = gtk_toggle_button_get_active (toggle_button);
  1145.  
  1146.   set_sensitive =
  1147.     gtk_object_get_data (GTK_OBJECT (toggle_button), "set_sensitive");
  1148.   while (set_sensitive)
  1149.     {
  1150.       gtk_widget_set_sensitive (set_sensitive, active);
  1151.       set_sensitive =
  1152.         gtk_object_get_data (GTK_OBJECT (set_sensitive), "set_sensitive");
  1153.     }
  1154.  
  1155.   set_sensitive =
  1156.     gtk_object_get_data (GTK_OBJECT (toggle_button), "inverse_sensitive");
  1157.   while (set_sensitive)
  1158.     {
  1159.       gtk_widget_set_sensitive (set_sensitive, ! active);
  1160.       set_sensitive =
  1161.         gtk_object_get_data (GTK_OBJECT (set_sensitive), "inverse_sensitive");
  1162.     }
  1163. }
  1164.  
  1165. /**
  1166.  * gimp_toggle_button_update:
  1167.  * @widget: A #GtkToggleButton.
  1168.  * @data:   A pointer to a #gint variable which will store the value of
  1169.  *          gtk_toggle_button_get_active().
  1170.  *
  1171.  * Note that this function calls gimp_toggle_button_sensitive_update().
  1172.  **/
  1173. void
  1174. gimp_toggle_button_update (GtkWidget *widget,
  1175.                gpointer   data)
  1176. {
  1177.   gint *toggle_val;
  1178.  
  1179.   toggle_val = (gint *) data;
  1180.  
  1181.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  1182.     *toggle_val = TRUE;
  1183.   else
  1184.     *toggle_val = FALSE;
  1185.  
  1186.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  1187. }
  1188.  
  1189. /**
  1190.  * gimp_radio_button_update:
  1191.  * @widget: A #GtkRadioButton.
  1192.  * @data:   A pointer to a #gint variable which will store the value of
  1193.  *          GPOINTER_TO_INT (gtk_object_get_user_data()).
  1194.  *
  1195.  * Note that this function calls gimp_toggle_button_sensitive_update().
  1196.  **/
  1197. void
  1198. gimp_radio_button_update (GtkWidget *widget,
  1199.               gpointer   data)
  1200. {
  1201.   gint *toggle_val;
  1202.  
  1203.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  1204.     {
  1205.       toggle_val = (gint *) data;
  1206.  
  1207.       *toggle_val =
  1208.     GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  1209.     }
  1210.  
  1211.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  1212. }
  1213.  
  1214. /**
  1215.  * gimp_menu_item_update:
  1216.  * @widget: A #GtkMenuItem.
  1217.  * @data:   A pointer to a #gint variable which will store the value of
  1218.  *          GPOINTER_TO_INT (gtk_object_get_user_data()).
  1219.  **/
  1220. void
  1221. gimp_menu_item_update (GtkWidget *widget,
  1222.                gpointer   data)
  1223. {
  1224.   gint *item_val;
  1225.  
  1226.   item_val = (gint *) data;
  1227.  
  1228.   *item_val = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  1229. }
  1230.  
  1231. /**
  1232.  * gimp_int_adjustment_update:
  1233.  * @adjustment: A #GtkAdjustment.
  1234.  * @data:       A pointer to a #gint variable which will store the
  1235.  *              @adjustment's value.
  1236.  *
  1237.  * Note that the #GtkAdjustment's value (which is a #gfloat) will be rounded
  1238.  * with RINT().
  1239.  **/
  1240. void
  1241. gimp_int_adjustment_update (GtkAdjustment *adjustment,
  1242.                 gpointer       data)
  1243. {
  1244.   gint *val;
  1245.  
  1246.   val = (gint *) data;
  1247.   *val = RINT (adjustment->value);
  1248. }
  1249.  
  1250. /**
  1251.  * gimp_uint_adjustment_update:
  1252.  * @adjustment: A #GtkAdjustment.
  1253.  * @data:       A pointer to a #guint variable which will store the
  1254.  *              @adjustment's value.
  1255.  *
  1256.  * Note that the #GtkAdjustment's value (which is a #gfloat) will be rounded
  1257.  * with (#guint) (value + 0.5).
  1258.  **/
  1259. void
  1260. gimp_uint_adjustment_update (GtkAdjustment *adjustment,
  1261.                  gpointer       data)
  1262. {
  1263.   guint *val;
  1264.  
  1265.   val = (guint *) data;
  1266.   *val = (guint) (adjustment->value + 0.5);
  1267. }
  1268.  
  1269. /**
  1270.  * gimp_float_adjustment_update:
  1271.  * @adjustment: A #GtkAdjustment.
  1272.  * @data:       A pointer to a #gfloat varaiable which willl store the
  1273.  *              @adjustment's value.
  1274.  **/
  1275. void
  1276. gimp_float_adjustment_update (GtkAdjustment *adjustment,
  1277.                   gpointer       data)
  1278. {
  1279.   gfloat *val;
  1280.  
  1281.   val = (gfloat *) data;
  1282.   *val = adjustment->value;
  1283. }
  1284.  
  1285. /**
  1286.  * gimp_double_adjustment_update:
  1287.  * @adjustment: A #GtkAdjustment.
  1288.  * @data:       A pointer to a #gdouble variable which will store the
  1289.  *              @adjustment's value.
  1290.  **/
  1291. void
  1292. gimp_double_adjustment_update (GtkAdjustment *adjustment,
  1293.                    gpointer       data)
  1294. {
  1295.   gdouble *val;
  1296.  
  1297.   val = (gdouble *) data;
  1298.   *val = adjustment->value;
  1299. }
  1300.  
  1301. /**
  1302.  * gimp_unit_menu_update:
  1303.  * @widget: A #GimpUnitMenu.
  1304.  * @data:   A pointer to a #GimpUnit variable which will store the unit menu's
  1305.  *          value.
  1306.  *
  1307.  * This callback can set the number of decimal digits of an arbitrary number
  1308.  * of #GtkSpinButton's. To use this functionality, attach the spinbuttons
  1309.  * as list of data pointers attached with gtk_object_set_data() with the
  1310.  * "set_digits" key.
  1311.  *
  1312.  * See gimp_toggle_button_sensitive_update() for a description of how
  1313.  * to set up the list.
  1314.  **/
  1315. void
  1316. gimp_unit_menu_update (GtkWidget *widget,
  1317.                gpointer   data)
  1318. {
  1319.   GimpUnit  *val;
  1320.   GtkWidget *spinbutton;
  1321.   gint       digits;
  1322.  
  1323.   val = (GimpUnit *) data;
  1324.   *val = gimp_unit_menu_get_unit (GIMP_UNIT_MENU (widget));
  1325.  
  1326.   digits = ((*val == GIMP_UNIT_PIXEL) ? 0 :
  1327.         ((*val == GIMP_UNIT_PERCENT) ? 2 :
  1328.          (MIN (6, MAX (3, gimp_unit_get_digits (*val))))));
  1329.  
  1330.   spinbutton =
  1331.     gtk_object_get_data (GTK_OBJECT (widget), "set_digits");
  1332.   while (spinbutton)
  1333.     {
  1334.       gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), digits);
  1335.       spinbutton = gtk_object_get_data (GTK_OBJECT (spinbutton), "set_digits");
  1336.     }
  1337. }
  1338.  
  1339. /*
  1340.  *  Helper Functions
  1341.  */
  1342.  
  1343. /**
  1344.  * gimp_table_attach_aligned:
  1345.  * @table:      The #GtkTable the widgets will be attached to.
  1346.  * @column:     The column to start with.
  1347.  * @row:        The row to attach the eidgets.
  1348.  * @label_text: The text for the #GtkLabel which will be attached left of the
  1349.  *              widget.
  1350.  * @xalign:     The horizontal alignment of the #GtkLabel.
  1351.  * @yalign:     The vertival alignment of the #GtkLabel.
  1352.  * @widget:     The #GtkWidget to attach right of the label.
  1353.  * @colspan:    The number of columns the widget will use.
  1354.  * @left_align: #TRUE if the widget should be left-aligned.
  1355.  *
  1356.  * Note that the @label_text can be #NULL and that the widget will be attached
  1357.  * starting at (@column + 1) in this case, too.
  1358.  **/
  1359. void
  1360. gimp_table_attach_aligned (GtkTable    *table,
  1361.                gint         column,
  1362.                gint         row,
  1363.                const gchar *label_text,
  1364.                gfloat       xalign,
  1365.                gfloat       yalign,
  1366.                GtkWidget   *widget,
  1367.                gint         colspan,
  1368.                gboolean     left_align)
  1369. {
  1370.   if (label_text)
  1371.     {
  1372.       GtkWidget *label;
  1373.  
  1374.       label = gtk_label_new (label_text);
  1375.       gtk_misc_set_alignment (GTK_MISC (label), xalign, yalign);
  1376.       gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
  1377.       gtk_table_attach (table, label,
  1378.             column, column + 1,
  1379.             row, row + 1,
  1380.             GTK_FILL, GTK_FILL, 0, 0);
  1381.       gtk_widget_show (label);
  1382.     }
  1383.  
  1384.   if (left_align)
  1385.     {
  1386.       GtkWidget *alignment;
  1387.  
  1388.       alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
  1389.       gtk_container_add (GTK_CONTAINER (alignment), widget);
  1390.       gtk_widget_show (widget);
  1391.  
  1392.       widget = alignment;
  1393.     }
  1394.  
  1395.   gtk_table_attach (table, widget,
  1396.             column + 1, column + 1 + colspan,
  1397.             row, row + 1,
  1398.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  1399.  
  1400.   gtk_widget_show (widget);
  1401. }
  1402.